/*
 * Function.cpp
 *
 *  Created on: 2013. 9. 12.
 *      Author: jjaehuny
 */

#include "Function.h"

#include "../Engine/Toolkit/HttpClient.h"

#include <sstream>
#include <time.h>
#include <stdio.h>

#include "../ack.h"
#include "../User.h"
#include "../Proxy.h"
#include "../NResource/Static.h"
#include "../NUtil/Utils.h"
#include "../GameLog.h"
#include "../NLogic/Buff.h"

#include "../xldata/pcnew.h"
#include "../xldata/pcstatup.h"
#include "../xldata/rank.h"
#include "../xldata/rank_score.h"

#include "Space.h"
#include "Battle.h"
#include "Static.h"
#include "Equip.h"
#include "Bag.h"
#include "VirtualCurrency.h"
#include "SocialInfo.h"
#include "Buff.h"

#include <boost/algorithm/string/replace.hpp>

#define PARTY_RANK_SCORE_CONST1		100	// 파티원이 1명일 경우 산출 한 Rank값이 x1
#define PARTY_RANK_SCORE_CONST2		60	// 파티원이 2명일 경우 산출 한 Rank값이 x0.6
#define PARTY_RANK_SCORE_CONST3		40	// 파티원이 3명일 경우 산출 한 Rank값이 x0.4

namespace ProjectZ { namespace NLogic { namespace NFunction {

const int INCREASE_SKILL_POINTS	= 1;
const int INCREASE_STAT_POINTS	= 3;

Function::Function() {

}

Function::~Function() {
}


unsigned int GetTickCount()
{
	// To REMOVE eclipse indexer error
	// code scrapped from <bit/time.h>
	#ifndef CLOCK_MONOTONIC
	#define CLOCK_MONOTONIC 1
	#endif

	struct timespec ts;
	clock_gettime(CLOCK_MONOTONIC, &ts);
	return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
}

void SendMyLevelExp(User * pUser, int rewardGold, bool bLevelUp)
{
/*	SC_REQ_MY_LEVEL_EXP		0x030B
	{
		u32 	u32gid;
		u8 	u8isLevelUp;
		u16 	u16level;
		u32 	u32exp;
		u32 	u32next_exp;
		u32		u32levelup_reward_gold;		// 레벨업 보상 골드
		u32		u32gold;					// 현재 보유 골드
		u8 	u8ChampLevel;

		if(u8ChampLevel > 0)
		{
			u32 	u32ChampExp;
			u32 	u32ChampMaxExp;
		}
	}*/

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	*pAck << static_cast<uint32_t>(pUser->GetUserSeq());
	*pAck << static_cast<uint8_t>(bLevelUp);
	*pAck << static_cast<uint16_t>(pUser->GetCharacterInfo().level);
	*pAck << static_cast<uint32_t>(pUser->GetCharacterInfo().exp);
	*pAck << static_cast<uint32_t>(getMaxExp(pUser));
//	*pAck << static_cast<uint32_t>(rewardGold);
//	*pAck << static_cast<uint32_t>(pUser->GetCharacterInfo().gold);
	*pAck << static_cast<uint8_t>(0);

	// 레벨이 0이면 아래 두개 보내지 말것
//	*pAck << static_cast<uint32_t>(0);	// 챔피언 경험치
//	*pAck << static_cast<uint32_t>(0);	// 챔피언 맥스 경험치

	pAck->MakePacket(CMD_SC_REQ_MY_LEVEL_EXP);
	pUser->Send(pAck);
}

int IncreaseExp(User * pUser, int exp)
{
	if( exp <= 0 )
	{
		return pUser->GetCharacterInfo().exp;
	}


	NResource::CommonData::Key clsKey(1,1);
	NResource::CommonData::Flyweight * pCommonResourceFly =
				NResource::Static::InstancePtr()->GetCommon()->GetFly(pUser, clsKey);
	if (pCommonResourceFly == NULL)
	{
		return 0;
	}

	if (static_cast<int>(pUser->GetCharacterInfo().level) >= pCommonResourceFly->_VALUE1)
		return pUser->GetCharacterInfo().exp;

	int value = pUser->GetCharacterInfo().exp + exp;
	int maxExp = getMaxExp(pUser);
	bool bLevelup = false;

	int rewardGold = 0;
	NResource::LevelupRewardResource::LevelupRewardData::Flyweight * pFly = NULL;

	while( value >= maxExp )
	{
		value -= maxExp;
		pUser->GetCharacterInfo().level++;
		bLevelup = true;
		NProxy::SetMainCharacterInfo(pUser);

		pFly = NResource::Static::InstancePtr()->GetLevelupResource()->GetFly(pUser);
		if (NULL != pFly)
		{
			rewardGold += pFly->_GOLD;
		}

		maxExp = getMaxExp(pUser);

		pUser->GetCharacterInfo().remain_stat_point += INCREASE_STAT_POINTS;

		// 스킬 포인트는 60레벨까지만 지급.
		if (61 > pUser->GetCharacterInfo().level)
		{
			pUser->GetCharacterInfo().remain_skill_point += INCREASE_SKILL_POINTS;
		}

		// change stat
		pUser->GetCharacterInfo().str += getIncreaseStat(pUser, STAT_STR);
		pUser->GetCharacterInfo().dex += getIncreaseStat(pUser, STAT_DEX);
		pUser->GetCharacterInfo().con += getIncreaseStat(pUser, STAT_CON);
		pUser->GetCharacterInfo().spi += getIncreaseStat(pUser, STAT_SPI);

		if (static_cast<int>(pUser->GetCharacterInfo().level) >= pCommonResourceFly->_VALUE1)
		{
			pUser->GetCharacterInfo().level = pCommonResourceFly->_VALUE1;
			pUser->GetCharacterInfo().exp = 0;
			break;
		}
	}

	// 캐릭터 레벨이 MAX레벨보다 작은 경우에만 남은 경험치 부여.
	if (static_cast<int>(pUser->GetCharacterInfo().level) < pCommonResourceFly->_VALUE1)
	{
		pUser->GetCharacterInfo().exp = value;
	}

	if (bLevelup)
	{
		//DEBUGLOG("%s level : %d", __FUNCTION__, pUser->GetCharacterInfo().level);
		pUser->GetUserInfo().array_Slot[pUser->GetCharacterInfo().slotindex].level = pUser->GetCharacterInfo().level;
		ModifyGold(pUser, rewardGold);
		NGameLog::LogGoldInfo(pUser, LEVELUP, rewardGold);
	}

	SendMyLevelExp(pUser, rewardGold, bLevelup);
	return pUser->GetCharacterInfo().exp;
}

int getMaxExp(User * pUser)
{
	NResource::LevelupExpResource::Flyweight * pFly = NResource::Static::Instance().GetLevelUpExpResource()->GetFly(pUser->GetCharacterInfo().level);

	if (NULL == pFly)
	{
		::Logger::GETLOG()->ToAll(::Logger::OBSERVER, "%s : user_seq=%d, character=%d, level=%d", __FUNCTION__, pUser->GetUserSeq(), pUser->GetCharacterInfo().characterseq, pUser->GetCharacterInfo().level);
		return 1056234480;
	}

	return pFly->_NEED_EXP;

//	int step1 = pow(pUser->GetCharacterInfo().level, 3);
//	int step2 = (int)step1 / 14;
//	int step3 = step2 + 12;
//	int step4 = step3 * pUser->GetCharacterInfo().level;
//	int step5 = step4 * 30;
//
//	return step5;
}

int getIncreaseStat(User * pUser, ESTATNAME statname)
{
	int class_type = pUser->GetCharacterInfo().classtype;
	if ( 0 > class_type || CLASS_TYPE_MAX <= class_type )
		return 0;
		
	int level = pUser->GetCharacterInfo().level;
	int needvalue = 0;

	switch( statname )
	{
	case STAT_STR:	needvalue = NXLData::stPcnew_Pcnew[class_type].STR_UP;	break;
	case STAT_DEX:	needvalue = NXLData::stPcnew_Pcnew[class_type].DEX_UP;	break;
	case STAT_CON:	needvalue = NXLData::stPcnew_Pcnew[class_type].CON_UP;	break;
	case STAT_SPI:	needvalue = NXLData::stPcnew_Pcnew[class_type].SPI_UP;	break;
	default:	return 0;
	}

	int ret = 0;
	if( level > 1 )
		ret = ( ( (level-1) % needvalue ) == 0 );

	return ret;
}

bool VCProcess(User * pUser, int vcIndex, int price)
{
	NResource::VCResource::Flyweight * pFly =
			NResource::Static::InstancePtr()->GetVCRef()->GetFly(vcIndex);

	if (pFly == NULL)
	{
		FILELOG("VCProcess : pFly is NULL!!!");
		return false;
	}

	int unitCount = 1;

	::Toolkit::Str<64> phoneNumber	= "";
	::Toolkit::Str<32> appVer		= "";
	::Toolkit::Str<32> lvStage		= "";
	sprintf(lvStage.str(), "%d", pUser->GetCharacterInfo().level);

	int vcPrice = 0;
	int NowZen = 0;

	// USER의 ZEN 갱신
	if (0 < price)
	{
		// ZEN 가격이 정해 지지 않은 경우 (ex. 젠회수, 강화석완료 등..)
		if (-1 == pFly->_VC_PRICE || 1 == pFly->_VC_PRICE)
		{
			bool bRet = pUser->GetVirtualCurrency()->AddZen(pFly->_VC_PRICE * price, NowZen);
			if (false == bRet)
				return false;

			vcPrice = pFly->_VC_PRICE * price;
		}
		// ZEN 가격은 정해져 있지만, 로직내에서 변동되는 경우 (ex. 마법 제련..)
		else
		{
			bool bRet = pUser->GetVirtualCurrency()->AddZen(-1 * price, NowZen);
			if (false == bRet)
				return false;

			vcPrice = -1 * price;
		}
	}
	else
	{
		//pUser->GetUserInfo().zen += pFly->_VC_PRICE;
		bool bRet = pUser->GetVirtualCurrency()->AddZen(pFly->_VC_PRICE, NowZen);
		if (false == bRet)
		{
			DEBUGLOG("VCProcess : false == pUser->GetVirtualCurrency()->AddZen(pFly->_VC_PRICE, NowZen)");
			return false;
		}
		vcPrice = pFly->_VC_PRICE;
	}

	::Database::Command::Auto clsAuto(::Database::GETCOMMANDPOOL());
	clsAuto->SetQueryType(::Database::Command::S_PROCEDURE);
	clsAuto->MakeQuery("call sp_insertVC('%s','%s','%s',%d,%d,'%s','%s',%d,%d,%d,%d,'%s',%d,%d,%d,%d,%d,%d,%d)",
			pUser->GetSocialID().c_str(),
			pUser->GetUserInfo().uuid.c_str(),
			phoneNumber.c_str(),
			pUser->GetUserInfo().company,
			pUser->GetUserInfo().sale_code,
			appVer.c_str(),
			lvStage.c_str(),
			pUser->GetUserInfo().main_slot_index,
			pFly->_VC_DIV_1,
			pFly->_VC_DIV_2,
			pFly->_VC_DIV_3,
			pFly->_VC_DESC.c_str(),
			vcPrice,
			unitCount,
			vcPrice,
			pFly->_VC_KIND,
			//pUser->GetUserInfo().zen,
			NowZen,
			0,
			0);

	if (false == ::Database::GETSESSION()->SyncExecute(pUser->GetUserInfo().shard_Item_db_type, clsAuto))
	{
		FILELOG("VCProcess : Procedure execute fail!! [%s]", clsAuto->GetQueryString());
		return false;
	}

	if (clsAuto->GetErrorIdx() != 0)
	{
		FILELOG("VCProcess : Procedure error!! [%s]", clsAuto->GetQueryString());
		return false;
	}

	return true;
}

time_t GetRecvStaminaInitTime()
{
	/*
	 * 스태미너 받기 초기화 시간
	 * 매일 오후 12시에 초기화 한다.
	 */

	if (true == ::ProjectZ::Config::Instance().GetResourceDatabase()._isTest)
	{
		// 테스트는 1시간 주기
		time_t initTime = time(NULL);
		struct tm * stInit = localtime(&initTime);

		if (stInit->tm_min >= 0 &&  stInit->tm_min < 20 )
		{
			stInit->tm_min = 0;
		}
		else if (stInit->tm_min >= 20 && stInit->tm_min < 40)
		{
			stInit->tm_min = 20;
		}
		else if (stInit->tm_min >= 40)
		{
			stInit->tm_min = 40;
		}

		stInit->tm_sec	= 0;
		stInit->tm_isdst = 0;

		return mktime(stInit);
	}

	time_t curTime;
	struct tm * stCurrent;

	time(&curTime);

	stCurrent = localtime(&curTime);

	int addSec = 0;

	if (12 > stCurrent->tm_hour)
		addSec = 3600 * 24;

	time_t initTime = curTime - addSec;
	struct tm * stInit = localtime(&initTime);

	stInit->tm_hour		= 12;
	stInit->tm_min		= 0;
	stInit->tm_sec		= 0;
	stInit->tm_isdst	= 0;

	return mktime(stInit);
}

time_t GetNextDailyMissionInitTime()
{
	if (true == ::ProjectZ::Config::Instance().GetResourceDatabase()._isTest)
	{
		// 테스트는 1시간 주기
		time_t initTime = time(NULL);
		struct tm * stInit = localtime(&initTime);

		if (stInit->tm_min >= 0 &&  stInit->tm_min < 20 )
		{
			stInit->tm_min = 20;
		}
		else if (stInit->tm_min >= 20 && stInit->tm_min < 40)
		{
			stInit->tm_min = 40;
		}
		else if (stInit->tm_min >= 40)
		{
			initTime += 3600;
			stInit = localtime(&initTime);
			stInit->tm_min = 0;
		}

		stInit->tm_sec	= 0;
		stInit->tm_isdst = 0;

		return mktime(stInit);
	}

	time_t curTime;
	struct tm * stCurrent;

	time(&curTime);

	stCurrent = localtime(&curTime);

	int addSec = 0;

	if (1 <= stCurrent->tm_hour)
		addSec = 3600 * 24;

	time_t initTime = curTime + addSec;
	struct tm * stInit = localtime(&initTime);

	stInit->tm_hour		= 1;
	stInit->tm_min		= 0;
	stInit->tm_sec		= 0;
	stInit->tm_isdst	= 0;

	return mktime(stInit);
}

time_t GetDailyMissionInitTime()
{
	/*
	 * 일일 미션 초기화 시간
	 * 매일 오전 1시에 초기화 한다.
	 */

	if (true == ::ProjectZ::Config::Instance().GetResourceDatabase()._isTest)
	{
		// 테스트는 1시간 주기
		time_t initTime = time(NULL);
		struct tm * stInit = localtime(&initTime);

		if (stInit->tm_min >= 0 &&  stInit->tm_min < 20 )
		{
			stInit->tm_min = 0;
		}
		else if (stInit->tm_min >= 20 && stInit->tm_min < 40)
		{
			stInit->tm_min = 20;
		}
		else if (stInit->tm_min >= 40)
		{
			stInit->tm_min = 40;
		}

		stInit->tm_sec	= 0;
		stInit->tm_isdst = 0;

		return mktime(stInit);
	}

	time_t curTime;
	struct tm * stCurrent;

	time(&curTime);

	stCurrent = localtime(&curTime);

	int addSec = 0;

	if (1 > stCurrent->tm_hour)
		addSec = 3600 * 24;

	time_t initTime = curTime - addSec;
	struct tm * stInit = localtime(&initTime);

	stInit->tm_hour		= 1;
	stInit->tm_min		= 0;
	stInit->tm_sec		= 0;
	stInit->tm_isdst	= 0;

	return mktime(stInit);
}

time_t GetMonthInitTime()
{
	if (true == ::ProjectZ::Config::Instance().GetResourceDatabase()._isTest)
	{
		// 테스트는 1시간 주기
		time_t initTime = time(NULL);
		struct tm * stInit = localtime(&initTime);

		stInit->tm_min	= 0;
		stInit->tm_sec	= 0;
		stInit->tm_isdst = 0;

		return mktime(stInit);
	}

	time_t initTime = time(NULL);
	struct tm * stInit = localtime(&initTime);

	int addSec = (stInit->tm_mday - 1) * 24 * 60 * 60;
	initTime -= addSec;
	stInit = localtime(&initTime);

	stInit->tm_hour	= 0;
	stInit->tm_min	= 0;
	stInit->tm_sec	= 0;
	stInit->tm_isdst = 0;

	return mktime(stInit);
}

time_t GetWeekInitTime()
{
	// test code
	if (true == ::ProjectZ::Config::Instance().GetResourceDatabase()._isTest)
		return GetHourInitTime(time(NULL));

	time_t curTime;
	struct tm * stCurrent;

	time(&curTime);

	stCurrent = localtime(&curTime);

	int addSec = 0;

	switch (stCurrent->tm_wday)
	{
	case 1:
		if (12 > stCurrent->tm_hour)
			addSec = 7 * 3600 * 24;
		else
			addSec = 0 * 3600 * 24;
		break;
	case 2: addSec = 1 * 3600 * 24; break;
	case 3: addSec = 2 * 3600 * 24; break;
	case 4: addSec = 3 * 3600 * 24; break;
	case 5: addSec = 4 * 3600 * 24; break;
	case 6: addSec = 5 * 3600 * 24; break;
	case 0: addSec = 6 * 3600 * 24; break;
	}

	time_t initTime = curTime - addSec;
	struct tm * stInit = localtime(&initTime);

//	stInit->tm_hour		= 0;
	stInit->tm_hour		= 12;
	stInit->tm_min		= 0;
	stInit->tm_sec		= 0;
	stInit->tm_isdst		= 0;

	return mktime(stInit);
}

time_t GetNextWeekInitTime()
{
	// test code
	if (true == ::ProjectZ::Config::Instance().GetResourceDatabase()._isTest)
	{
		int rankCycle = ::ProjectZ::Config::Instance().GetResourceFile()._rankCycle;
		return GetHourInitTime(time(NULL) + rankCycle);
	}

	time_t curTime;
	struct tm * stCurrent;

	time(&curTime);

	stCurrent = localtime(&curTime);

	int addSec = 0;

	switch (stCurrent->tm_wday)
	{
	case 1:
		if (12 > stCurrent->tm_hour)
			addSec = 0;
		else
			addSec = 7 * 3600 * 24;
		break;
	case 2: addSec = 6 * 3600 * 24; break;
	case 3: addSec = 5 * 3600 * 24; break;
	case 4: addSec = 4 * 3600 * 24; break;
	case 5: addSec = 3 * 3600 * 24; break;
	case 6: addSec = 2 * 3600 * 24; break;
	case 0: addSec = 1 * 3600 * 24; break;
	}

	time_t initTime = curTime + addSec;
	struct tm * stInit = localtime(&initTime);

//	stInit->tm_hour		= 0;
	stInit->tm_hour		= 12;
	stInit->tm_min		= 0;
	stInit->tm_sec		= 0;
	stInit->tm_isdst		= 0;

	return mktime(stInit);
}

time_t GetDailyInitTime(time_t initTime)
{
	if (true == ::ProjectZ::Config::Instance().GetResourceDatabase()._isTest)
	{
//		return GetHourInitTime(initTime);

		struct tm * tm;
		tm = localtime(&initTime);

		if (tm->tm_min >= 0 &&  tm->tm_min < 10 )
			tm->tm_min = 0;
		if (tm->tm_min >= 10 && tm->tm_min < 20)
			tm->tm_min = 10;
		if (tm->tm_min >= 20 && tm->tm_min < 30)
			tm->tm_min = 20;
		if (tm->tm_min >= 30 && tm->tm_min < 40)
			tm->tm_min = 30;
		if (tm->tm_min >= 40 && tm->tm_min < 50)
			tm->tm_min = 40;
		if (tm->tm_min >= 50)
			tm->tm_min = 50;

		tm->tm_sec      = 0;
		tm->tm_isdst    = 0;

		return mktime(tm);
	}

	struct tm * tm;
	tm = localtime(&initTime);

	tm->tm_hour		= 0;
	tm->tm_min		= 0;
	tm->tm_sec		= 0;
	tm->tm_isdst	= 0;

	return mktime(tm);
}

time_t GetHourInitTime(time_t initTime)
{
	struct tm * tm;
	tm = localtime(&initTime);

	int rankCycle = ::ProjectZ::Config::Instance().GetResourceFile()._rankCycle;

	switch (rankCycle)
	{
	case 600:	// 10분
		if (tm->tm_min >= 0 &&  tm->tm_min < 10 )
			tm->tm_min = 0;
		if (tm->tm_min >= 10 && tm->tm_min < 20)
			tm->tm_min = 10;
		if (tm->tm_min >= 20 && tm->tm_min < 30)
			tm->tm_min = 20;
		if (tm->tm_min >= 30 && tm->tm_min < 40)
			tm->tm_min = 30;
		if (tm->tm_min >= 40 && tm->tm_min < 50)
			tm->tm_min = 40;
		if (tm->tm_min >= 50)
			tm->tm_min = 50;
		break;

	case 1200:	// 20분
		if (tm->tm_min >= 0 &&  tm->tm_min < 20 )
			tm->tm_min = 0;
		if (tm->tm_min >= 20 && tm->tm_min < 40)
			tm->tm_min = 20;
		if (tm->tm_min >= 40)
			tm->tm_min = 40;
		break;

	case 1800:	// 30분
		if (tm->tm_min >= 0 &&  tm->tm_min < 30 )
			tm->tm_min = 0;
		if (tm->tm_min >= 30)
			tm->tm_min = 30;
		break;

	case 86400 :	// 1 Day
		if (12 > tm->tm_hour)
		{
			initTime -= rankCycle;
			tm = localtime(&initTime);
		}
		tm->tm_hour		= 12;
		tm->tm_min		= 0;
		tm->tm_sec		= 0;
		tm->tm_isdst	= 0;

		return mktime(tm);

	default:
		tm->tm_min		= 0;
		break;

	}

#if 0	// 10분
	if (tm->tm_min >= 0 &&  tm->tm_min < 10 )
		tm->tm_min = 0;
	if (tm->tm_min >= 10 && tm->tm_min < 20)
		tm->tm_min = 10;
	if (tm->tm_min >= 20 && tm->tm_min < 30)
		tm->tm_min = 20;
	if (tm->tm_min >= 30 && tm->tm_min < 40)
		tm->tm_min = 30;
	if (tm->tm_min >= 40 && tm->tm_min < 50)
		tm->tm_min = 40;
	if (tm->tm_min >= 50)
		tm->tm_min = 50;
#endif

#if 0	// 20분
	if (tm->tm_min >= 0 &&  tm->tm_min < 20 )
		tm->tm_min = 0;
	if (tm->tm_min >= 20 && tm->tm_min < 40)
		tm->tm_min = 20;
	if (tm->tm_min >= 40)
		tm->tm_min = 40;
#endif

#if 0	// 30분
	if (tm->tm_min >= 0 &&  tm->tm_min < 30 )
		tm->tm_min = 0;
	if (tm->tm_min >= 30)
		tm->tm_min = 30;
#endif

#if 0	// 60분
	tm->tm_min		= 0;
#endif

	tm->tm_sec      = 0;
	tm->tm_isdst    = 0;

	return mktime(tm);
}

int GetBagSlotMaxOpenCount(INVEN_BAG_TYPE eBagType)
{
	switch (eBagType)
	{
	case BAG_TYPE_NORMAL:		return 52;
	case BAG_TYPE_ACCESSORY:	return 52;
	case BAG_TYPE_MISC:			return 32;
	case BAG_TYPE_TITLE:		return 32;
	case BAG_TYPE_WAREHOUSE:	return 8;
	case BAG_TYPE_FAIRY:		return 60;
	case BAG_TYPE_BATTLE_PET:	return 80;
	default:					return 0;
	}
}

int GetMonsterHP(User * pUser, int level, int mode, int dungeon, int playerCount, bool bLegend, bool bBoss, bool bBattlepet)
{
	/*
	 * 몬스터 HP 계산
	 * (레벨^2)*30+20*3(상수)*레벨+140
	 */

	NResource::BalanceData * pBalance = NResource::Static::InstancePtr()->GetBalance()->GetBalancePtr(pUser);
	if (NULL == pBalance)
	{
		DEBUGLOG("%s : pBalance is NULL!", __FUNCTION__);
		return 0;
	}

	if (true == bBattlepet)
	{
		int HP = (pow(level, 2) * 19) + (20 * pBalance->GetValue(EM_MOB_MAX_HP_VALUE) * level) + 140;
		return HP;
	}

	NResource::MonsterResource::Flyweight * pFly = NResource::Static::InstancePtr()->GetMonsterResource()->GetFly(dungeon);
	if (NULL == pFly)
	{
		DEBUGLOG("%s : pFly is NULL!", __FUNCTION__);
		return 0;
	}

//	int HP = (pow(level, 2) * 19) + (20 * pBalance->GetValue(EM_MOB_MAX_HP_VALUE) * level) + 140;
	int HP = (pow(level, 2) * 19) + (20 * pFly->_HP_CONST * level) + 140;

	// 던전 모드별 가중치 부여
	switch (mode)
	{
	case 0 : HP = (HP * pBalance->GetValue(EM_NORMAL_MOB_HP_CONST)) / 100; break;
	case 1 : HP = (HP * pBalance->GetValue(EM_HARD_MOB_HP_CONST)) / 100; break;
	case 2 : HP = (HP * pBalance->GetValue(EM_HELL_MOB_HP_CONST)) / 100; break;
	}

	// 파티 인원수 별 가중치 부여
	switch (playerCount)
	{
	case 1 : HP = (HP * pBalance->GetValue(EM_USER1_MOB_HP_CONST)) / 100; break;
	case 2 : HP = (HP * pBalance->GetValue(EM_USER2_MOB_HP_CONST)) / 100; break;
	case 3 : HP = (HP * pBalance->GetValue(EM_USER3_MOB_HP_CONST)) / 100; break;
	}

	// 레전드 몬스터 가중치 부역
	if (bLegend)
	{
		//HP = NUtil::AddPercentage(HP, pBalance->GetValue(EM_LEGEND_ADD_HP));
		HP = (HP * pFly->_LEGEND_HP_CONST) / 100;
	}

	// 보스 몬스터 가중치 부여
	if (bBoss)
	{
		HP = (HP * pFly->_BOSS_HP_CONST) / 100;
	}

	DEBUGLOG(" GetMonsterHP : level=%d, mode=%d, dungeon_id=%d, player_conunt=%d, is_legend=%d, is_boss=%d, hp=%d",
			level, mode, dungeon, playerCount, bLegend, bBoss, HP);

	return HP;
}

int GetAdjustHP(User * pUser, bool bPvP)
{
	NResource::AIVariationData::Flyweight * pFly = NULL;

	if (true == bPvP)
	{
		pFly = NResource::Static::InstancePtr()->GetAIVariation()->GetFly(pUser, pUser->GetCharacterInfo().level);
	}
	else
	{
		pFly = NResource::Static::InstancePtr()->GetAIVariation()->GetFly(pUser, pUser->GetCharacterInfo().level, false);
	}

	if (NULL == pFly)
	{
		PROCESSLOG("%s:%s -> pFly is NULL!! userlevel=%d", __FILE__, __FUNCTION__, pUser->GetCharacterInfo().level);
		return 0;
	}

	int addHP = 0;
	switch (pUser->GetCharacterInfo().classtype)
	{
	case CLASS_TYPE_SLASHER:	addHP = pFly->_SLASHER; break;
	case CLASS_TYPE_RANGER:		addHP = pFly->_RANGER; break;
	case CLASS_TYPE_FIGHTER:	addHP = pFly->_FIGHTER; break;
	case CLASS_TYPE_MAGICIAN:	addHP = pFly->_MAGICIAN; break;
	case CLASS_TYPE_ASSASSIN:	addHP = pFly->_ASSASSIN; break;
	case CLASS_TYPE_PALADIN:	addHP = pFly->_PALADIN; break;
	}

	return addHP;
}

int GetPKSessionRank(int userseq, NLogic::Space *pSpace)
{
	int rank = 1;
	auto pMyBattle = pSpace->FindBattle(userseq);
	if( NULL == pMyBattle )
		return 0;

	auto itr = pSpace->GetBattleTree().begin();
	for( ; itr != pSpace->GetBattleTree().end() ; ++itr)
	{
		NLogic::Battle * pBattle = itr->second;

		if( pMyBattle == pBattle )
			continue;

		if(pMyBattle->GetData().attack_point < pBattle->GetData().attack_point)
		{
			rank++;
		}
		else if(pMyBattle->GetData().attack_point == pBattle->GetData().attack_point)
		{
			if(pMyBattle->GetData().level == pBattle->GetData().level)
			{
				if(pMyBattle->GetData().userseq > pBattle->GetData().userseq)
				{
					rank++;
				}
			}
			else if(pMyBattle->GetData().level > pBattle->GetData().level)
			{
				rank++;
			}
		}
	}

	return rank;
}

int GetDefaultStat(int classtype, ESTATNAME statname)
{
	if ( 0 > classtype || CLASS_TYPE_MAX <= classtype )
		return 1;
		
	switch (statname)
	{
	case STAT_STR:
		return NXLData::stPcnew_Pcnew[classtype].STR_NEW;
	case STAT_DEX:
		return NXLData::stPcnew_Pcnew[classtype].DEX_NEW;
	case STAT_CON:
		return NXLData::stPcnew_Pcnew[classtype].CON_NEW;
	case STAT_SPI:
		return NXLData::stPcnew_Pcnew[classtype].SPI_NEW;
	}

	DEBUGLOG("GetDefaultStat : wrong statname=%d", statname);

	return 0;
}

int GetStatUpConst(int classtype, ESTATNAME statname)
{
	if ( 0 > classtype || CLASS_TYPE_MAX <= classtype )
		return 1;
		
	switch (statname)
	{
	case STAT_STR:
		return NXLData::stPcnew_Pcnew[classtype].STR_UP;
	case STAT_DEX:
		return NXLData::stPcnew_Pcnew[classtype].DEX_UP;
	case STAT_CON:
		return NXLData::stPcnew_Pcnew[classtype].CON_UP;
	case STAT_SPI:
		return NXLData::stPcnew_Pcnew[classtype].SPI_UP;
	}

	DEBUGLOG("GetStatUpConst : wrong statname=%d", statname);

	return 0;
}

bool IsInternalIP(std::string &str)
{
	std::string ip1("192.");
	std::string ip2("10.");

	if(ip1.compare(0, ip1.size(), str, 0, ip1.size()) == 0)
	{
		return true;
	}
	else if(ip2.compare(0, ip2.size(), str, 0, ip2.size()) == 0)
	{
		return true;
	}

	return false;
}
/*
//void kakaoPaymentLogCallback(int httpResult, const char* data)
//{
//	PROCESSLOG("%s : Http Result Code=%d, Data=[%s]", __FUNCTION__, httpResult, data);
//}
//
//void SendKakaoPaymentLog(User * pUser, int nPrice, int buySeq)
//{
//    char param[1024] = {0};
//	snprintf(param, 1024, "{\n \
//							\"client_id\" : \"90315658209776224\", \n \
//							\"secret_key\" : \"f1a48f969b2385effa136e68c50f04c59ab31b46c41272a5ae929d634ba80356\", \n \
//							\"service_user_id\" : \"%s\", \n \
//							\"platform\" : \"%s\", \n \
//							\"price\" : %d, \n \
//							\"currency\" : \"%s\", \n \
//							\"os\" : \"%s\", \n \
//							\"country_iso\" : \"KR\", \n \
//							\"buy_no\" : %d \n \
//						   }",
//						   pUser->GetSocialID().c_str(),
//						   pUser->GetCompany() == 4 ? "apple" : "google",
//						   nPrice,
//						   pUser->GetCompany() == 4 ? "USD" : "KRW",
//						   pUser->GetCompany() == 4 ? "ios" : "android",
//						   buySeq);
//
//	PROCESSLOG("%s : kakao payment param=[%s]", __FUNCTION__, param);
//
//	::Toolkit::HttpClient client("https://gameapi.kakao.com");
//	client.SetHeader("Content-type", "application/x-www-form-urlencoded");
//	client.Post("payment_v1/payments.json", param, kakaoPaymentLogCallback);
//}
 *
 */

void SendPush_android(const char * key, const char * uuid)
{
/*
//	std::string json = ::ProjectZ::NUtil::String::Concat(
//						  "{\n \
//							\"platform\" : \"android\", \n \
//							\"gid\" : \"27389\", \n \
//							\"sale_code\" : \"12345\", \n \
//							\"target_uuids : [", uuid, "] \n \
//							\"message\" : \"TEST PUSH\", \n \
//							\"right_button\" : \"TEST\", \n \
//							\"badge\" : \"1\", \n \
//							\"sound\" : \"default\", \n \
//						   }");
//	::ProjectZ::NUtil::HttpClient client("http://push3.gamevil.com");
//	client.SetHeader("GV-API-KEY", key);
//	client.Post("api/s_send_push.php", json.c_str(), kakao_PaymentCallback);
*/
}

void SendPush_ios(const char * key, const char * uuid)
{
/*
//	std::string json = ::ProjectZ::NUtil::String::Concat(
//						  "{\n \
//							\"platform\" : \"ios\", \n \
//							\"gid\" : \"27389\", \n \
//							\"sale_code\" : \"12345\", \n \
//							\"target_uuids : [", uuid, "] \n \
//							\"message\" : \"TEST PUSH\", \n \
//							\"right_button\" : \"TEST\", \n \
//							\"badge\" : \"1\", \n \
//							\"sound\" : \"default\", \n \
//						   }");
//	::ProjectZ::NUtil::HttpClient client("http://push3.gamevil.com");
//	client.SetHeader("GV-API-KEY", key);
//	client.Post("api/s_send_push.php", json.c_str(), kakao_PaymentCallback);
 *
 */
}

//static void Callback(int httpResult, const char* data)
//{
//	printf("%s : Http Result Code=%d, Data=[%s] \n", __FUNCTION__, httpResult, data);
//}

typedef void(*GCMCallback)(void *arg);

typedef struct __GCMCallbackData
{
	GCMCallback func;
	void            *arg;
} GCMCallbackData;

struct MemoryStruct {
	char *memory;
	size_t size;
	GCMCallbackData *CallbackData;
};


static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
	size_t realsize = size * nmemb;
	struct MemoryStruct *mem = (struct MemoryStruct *)userp;

	mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
	if (mem->memory == NULL)
	{
		/* out of memory! */
		fprintf(stderr, "not enough memory (realloc returned NULL), abort!!\n");
		return 0;
	}

	memcpy(&(mem->memory[mem->size]), contents, realsize);
	mem->size += realsize;
	mem->memory[mem->size] = 0;

	return realsize;
}


void call_back(void * arg)
{
}

void SendPush(unsigned int userseq, std::string msg)
{
	::Database::Command::Auto clsAuto(::Database::GETCOMMANDPOOL());
	clsAuto->SetQueryType(::Database::Command::SELECT);
	clsAuto->MakeQuery("SELECT company, sale_cd, uuid FROM info_user WHERE user_seq = %d", userseq);
	if (false == ::Database::GETSESSION()->SyncExecute(1, clsAuto))
		return;

	if( clsAuto->GetErrorIdx() != 0 )
		return;

	if (0 == clsAuto->ResultRowCount())
		return;

	int company = 0;
	int sale_cd = 0;
	::Toolkit::Str<81> uuid;

	while( clsAuto->Next() )
	{
		clsAuto->GetRecord() >> company >> sale_cd >> uuid;
	}



	if (4 == company)
	{
//		std::stringstream stream;
//		stream << "{\n";
//		stream << "\"platform\" : \"ios\", \n";
//		stream << "\"gid\" : \"27389\", \n";
//		stream << "\"sale_code\" : \"37\", \n";
//		stream << "\"target_uuids\" : [\"" << uuid.c_str() << "\"], \n";
//		stream << "\"message\" : \"" <<  msg.c_str() << "\", \n";
//		stream << "\"right_button\" : \" \", \n";
//		stream << "\"badge\" : \"1\", \n";
//		stream << "\"sound\" : \"default\", \n";
//		stream << "}";
//
//		::Toolkit::HttpClient client("http://push3.gamevil.com/");
//		client.SetHeader("Content-type", "application/json");
//		client.SetHeader("GV-API-KEY", "2b5b97b6aaecea5ae3a47adf2a6b4890");
//		bool bRet = client.Post("api/s_send_push.php", stream.str().c_str(), Callback);

		struct curl_slist * headmsg = NULL;
		char public_key[1024];

		memset( public_key, 0x00, sizeof(public_key) );
		sprintf( public_key, "GV-API-KEY:2b5b97b6aaecea5ae3a47adf2a6b4890");
		headmsg = curl_slist_append( headmsg, public_key );

		json_object *arr_jstr = json_object_new_array();
		json_object *jobj_send_body = json_object_new_object();

		{
			json_object *jstr = json_object_new_string("ios");
			json_object_object_add(jobj_send_body, "platform", jstr );
		}

		{
			json_object *jstr = json_object_new_string("27389");
			json_object_object_add(jobj_send_body, "gid", jstr );
		}

		{
			json_object *jstr = json_object_new_string("38");
			json_object_object_add(jobj_send_body, "sale_code", jstr );
		}


		{
			json_object *arr_jstr1 = json_object_new_string(uuid.c_str());
			json_object_array_add( arr_jstr, arr_jstr1 );
			json_object_object_add(jobj_send_body, "target_uuids", arr_jstr );
		}

		{
			json_object *jstr = json_object_new_string(msg.c_str());
			json_object_object_add(jobj_send_body, "message", jstr );
		}

		{
			json_object *jstr = json_object_new_string("OK");
			json_object_object_add(jobj_send_body, "right_button", jstr );
		}

		{
			json_object *jstr = json_object_new_string("1");
			json_object_object_add(jobj_send_body, "badge", jstr );
		}

		{
			json_object *jstr = json_object_new_string("default");
			json_object_object_add(jobj_send_body, "sound", jstr );
		}

		const char *postmsg = json_object_to_json_string(jobj_send_body);
		int postlen = strlen(postmsg);

		DEBUGLOG("body[%d:%s]\n", postlen, postmsg );

		// post to send
		CURL *curl;
		CURLcode res;
		struct MemoryStruct chunk;
		chunk.memory = (char *)malloc(1);
		chunk.size = 0;
		chunk.CallbackData = NULL;
		curl = curl_easy_init();

		struct curl_slist *headers = NULL;
		curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postlen);
		curl_easy_setopt(curl, CURLOPT_URL, "http://push3.gamevil.com/api/s_send_push.php?encoding=json" );
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
		curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 1);
		curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15);
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postmsg);
		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);    /**/
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headmsg );
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);

		res = curl_easy_perform(curl);

		fprintf(stderr, "after %d:%s\n", res, chunk.memory);
		fprintf(stderr, "error:%s\n", curl_easy_strerror(res));

		curl_easy_cleanup(curl);
		curl_slist_free_all(headers);

		int ret_status = -1;

		if( res == CURLE_OK ) {
				DEBUGLOG("curl_easy_perform result=%s\n", (char*)chunk.memory);
		}
		else {
				ret_status = res;
				DEBUGLOG("curl_easy_perform result=%d\n", ret_status);
		}

		json_object_put(jobj_send_body);
		json_object_put(arr_jstr);
		free(chunk.memory);
	}
	else if (5 == company)
	{
		struct curl_slist * headmsg = NULL;
		char public_key[1024];

		memset( public_key, 0x00, sizeof(public_key) );
		sprintf( public_key, "GV-API-KEY:2b5b97b6aaecea5ae3a47adf2a6b4890");
		headmsg = curl_slist_append( headmsg, public_key );

		json_object *arr_jstr = json_object_new_array();
		json_object *jobj_send_body = json_object_new_object();

		{
			json_object *jstr = json_object_new_string("android");
			json_object_object_add(jobj_send_body, "platform", jstr );
		}

		{
			json_object *jstr = json_object_new_string("27389");
			json_object_object_add(jobj_send_body, "gid", jstr );
		}

		{
			json_object *jstr = json_object_new_string("37");
			json_object_object_add(jobj_send_body, "sale_code", jstr );
		}


		{
			json_object *arr_jstr1 = json_object_new_string(uuid.c_str());
			json_object_array_add( arr_jstr, arr_jstr1 );
			json_object_object_add(jobj_send_body, "target_uuids", arr_jstr );
		}

		{
			json_object *jstr = json_object_new_string(msg.c_str());
			json_object_object_add(jobj_send_body, "message", jstr );
		}

		{
			json_object *jstr = json_object_new_string("gamevil");
			json_object_object_add(jobj_send_body, "right_button", jstr );
		}

		{
			json_object *jstr = json_object_new_string("gamevil");
			json_object_object_add(jobj_send_body, "sender", jstr );
		}

		{
			json_object *jstr = json_object_new_string("TEST");
			json_object_object_add(jobj_send_body, "title", jstr );
		}

		{
			json_object *jstr = json_object_new_string("gamevil");
			json_object_object_add(jobj_send_body, "left_button", jstr );
		}

		{
			json_object *jstr = json_object_new_string("http://www.gamevil.com");
			json_object_object_add(jobj_send_body, "callback_url", jstr );
		}

		{
			json_object *jstr = json_object_new_string("1");
			json_object_object_add(jobj_send_body, "push_type", jstr );
		}

		{
			json_object *jstr = json_object_new_string("1");
			json_object_object_add(jobj_send_body, "display_type", jstr );
		}

		{
			json_object *jstr = json_object_new_string("10");
			json_object_object_add(jobj_send_body, "popup_time", jstr );
		}

		{
			json_object *jstr = json_object_new_string("");
			json_object_object_add(jobj_send_body, "banner_img", jstr );
		}

	//	{
	//		json_object *jstr = json_object_new_string("1");
	//		json_object_object_add(jobj_send_body, "badge", jstr );
	//	}
	//
	//	{
	//		json_object *jstr = json_object_new_string("default");
	//		json_object_object_add(jobj_send_body, "sound", jstr );
	//	}

		const char *postmsg = json_object_to_json_string(jobj_send_body);
		int postlen = strlen(postmsg);

		DEBUGLOG("body[%d:%s]\n", postlen, postmsg );

		// post to send
		CURL *curl;
		CURLcode res;
		struct MemoryStruct chunk;
		chunk.memory = (char *)malloc(1);
		chunk.size = 0;
		chunk.CallbackData = NULL;
		curl = curl_easy_init();

		struct curl_slist *headers = NULL;
		curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postlen);
		curl_easy_setopt(curl, CURLOPT_URL, "http://push3.gamevil.com/api/s_send_push.php?encoding=json" );
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
		curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 1);
		curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15);
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postmsg);
		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);    /**/
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headmsg );
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);

		res = curl_easy_perform(curl);

		fprintf(stderr, "after %d:%s\n", res, chunk.memory);
		fprintf(stderr, "error:%s\n", curl_easy_strerror(res));

		curl_easy_cleanup(curl);
		curl_slist_free_all(headers);

		int ret_status = -1;

		if( res == CURLE_OK ) {
			DEBUGLOG("curl_easy_perform result=%s\n", (char*)chunk.memory);
		}
		else {
				ret_status = res;
				DEBUGLOG("curl_easy_perform result=%d\n", ret_status);
		}

		json_object_put(jobj_send_body);
		json_object_put(arr_jstr);
		free(chunk.memory);

//		std::stringstream stream;
//		stream << "{\n";
//		stream << "\"platform\" : \"android\", \n";
//		stream << "\"gid\" : \"27389\", \n";
//		stream << "\"sale_code\" : \"37\", \n";
//		stream << "\"target_uuids\" : [\"" << uuid.c_str() << "\"], \n";
//		stream << "\"message\" : \"" <<  msg.c_str() << "\", \n";
//		stream << "\"right_button\" : \" \", \n";
//		stream << "\"badge\" : \"1\", \n";
//		stream << "\"sound\" : \"default\", \n";
//		stream << "}";
//
//		::Toolkit::HttpClient client("http://push3.gamevil.com/");
//		client.SetHeader("Content-type", "application/json");
//		client.SetHeader("GV-API-KEY", "2b5b97b6aaecea5ae3a47adf2a6b4890");
//		bool bRet = client.Post("api/s_send_push.php", stream.str().c_str(), Callback);
	}
	else
	{

	}


}

void SendCPI(const char * pData)
{
//	::ProjectZ::NUtil::HttpClient client("http://advanceservice.gamevil.com");
//	client.Post("gv_request_gift_vc/put=", pData, kakao_PaymentCallback);
}

void SendMyWallet(User * pUser)
{
	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();

	*pAck << static_cast<int16_t>(ACK_OK);
	*pAck << pUser->GetCharacterInfo().gold;
	*pAck << pUser->GetVirtualCurrency()->GetZen();

	pAck->MakePacket(CMD_SC_MY_WALLET);
	pUser->Send(pAck);
}

void ModifyGold(User * pUser, int gold)
{
	if ( 0 == gold )
		return;

	if (gold < 0 && pUser->GetCharacterInfo().gold < ( gold * -1 ))
		pUser->GetCharacterInfo().gold = 0;
	else
		pUser->GetCharacterInfo().gold += gold;

	if (MAX_GOLD < pUser->GetCharacterInfo().gold)
		pUser->GetCharacterInfo().gold = MAX_GOLD;

	if (gold < 0)
	{
		pUser->FlushCharacterInfo();
	}
	else
	{
		pUser->FlushCharacterInfoCache();
	}

	SendMyWallet(pUser);
}

bool SendMail(User * pUser, NLogic::MailBox::Mail::Data & data)
{
    NLogic::MailBox::Mail * pMail   = NLogic::Static::InstancePtr()->GETMAILPOOL()->NEW();
    pMail->Open_Normal(data, pUser);

    if (false == pMail->InsertDatabaseMail())
    {
        NLogic::Static::InstancePtr()->GETMAILPOOL()->DEL(pMail);
        return false;
    }
    NLogic::Static::InstancePtr()->GETMAILPOOL()->DEL(pMail);

    return true;

}

int GetRank(User * pUser, NLogic::Space * pSpace)
{
	int table_id = pSpace->GetData()._table_id;
	int player_count = pSpace->GetUserTree().size();

	const NXLData::RANK_SCORE_RANK_SCORE_CONDITION *point = &NXLData::stRank_Score_Rank_Score_Condition[0];
	const NXLData::RANK_SCORE_RANK_SCORE_CONDITION *data  = &NXLData::stRank_Score_Rank_Score_Condition[table_id];

	int rank_point = 0;

	// 던전 클리어 타임
	if (pUser->GetBattle()->GetData().clear_second <= data->CLEAR_TIME1)
	{
		rank_point += point->CLEAR_TIME1;
	}
	else if (pUser->GetBattle()->GetData().clear_second <= data->CLEAR_TIME2)
	{
		rank_point += point->CLEAR_TIME2;
	}
	else if (pUser->GetBattle()->GetData().clear_second <= data->CLEAR_TIME3)
	{
		rank_point += point->CLEAR_TIME3;
	}

	// 최대 콤보
	if (pUser->GetBattle()->GetData().combo_max >= data->MAX_COMBO1)
	{
		rank_point += point->MAX_COMBO1;
	}
	else if (pUser->GetBattle()->GetData().combo_max >= data->MAX_COMBO2)
	{
		rank_point += point->MAX_COMBO2;
	}
	else if (pUser->GetBattle()->GetData().combo_max >= data->MAX_COMBO3)
	{
		rank_point += point->MAX_COMBO3;
	}

	// 누적 피해
	if (pUser->GetBattle()->GetData().acc_damage >= data->ACC_DAMEGE_TO_MOB1)
	{
		rank_point += point->ACC_DAMEGE_TO_MOB1;
	}
	else if (pUser->GetBattle()->GetData().acc_damage >= data->ACC_DAMEGE_TO_MOB2)
	{
		rank_point += point->ACC_DAMEGE_TO_MOB2;
	}
	else if (pUser->GetBattle()->GetData().acc_damage >= data->ACC_DAMEGE_TO_MOB3)
	{
		rank_point += point->ACC_DAMEGE_TO_MOB3;
	}

	// 몬스터 처치
	if (pUser->GetBattle()->GetData().kill_monster_num >= data->MAX_KILLMONSTER1)
	{
		rank_point += point->MAX_KILLMONSTER1;
	}
	else if (pUser->GetBattle()->GetData().kill_monster_num >= data->MAX_KILLMONSTER2)
	{
		rank_point += point->MAX_KILLMONSTER2;
	}
	else if (pUser->GetBattle()->GetData().kill_monster_num >= data->MAX_KILLMONSTER3)
	{
		rank_point += point->MAX_KILLMONSTER3;
	}

	// 받은 피해
	if (pUser->GetBattle()->GetData().acc_get_damage <= data->ACC_DAMAGE_TO_PC1)
	{
		rank_point += point->ACC_DAMAGE_TO_PC1;
	}
	else if (pUser->GetBattle()->GetData().acc_get_damage <= data->ACC_DAMAGE_TO_PC2)
	{
		rank_point += point->ACC_DAMAGE_TO_PC2;
	}
	else if (pUser->GetBattle()->GetData().acc_get_damage <= data->ACC_DAMAGE_TO_PC3)
	{
		rank_point += point->ACC_DAMAGE_TO_PC3;
	}

	// 보스 몬스터 피해
	if (pUser->GetBattle()->GetData().acc_damage_boss_damage >= data->ACC_DAMAGE_TO_BOSS1)
	{
		rank_point += point->ACC_DAMAGE_TO_BOSS1;
	}
	else if (pUser->GetBattle()->GetData().acc_damage_boss_damage >= data->ACC_DAMAGE_TO_BOSS2)
	{
		rank_point += point->ACC_DAMAGE_TO_BOSS2;
	}
	else if (pUser->GetBattle()->GetData().acc_damage_boss_damage >= data->ACC_DAMAGE_TO_BOSS3)
	{
		rank_point += point->ACC_DAMAGE_TO_BOSS3;
	}

	// 파티원의 수에 따라 랭크 계산
	if (player_count == 1)
	{
		rank_point = rank_point * (PARTY_RANK_SCORE_CONST1 / 100.0);
	}
	else if (player_count == 2)
	{
		rank_point = rank_point * (PARTY_RANK_SCORE_CONST2 / 100.0);
	}
	else if (player_count == 3)
	{
		rank_point = rank_point * (PARTY_RANK_SCORE_CONST3 / 100.0);
	}

	if (rank_point > 15)
	{
		rank_point = 15;
	}

	int idx		= NXLData::RANK_RANK_MAX - 1;
	int rank	= NXLData::RANK_RANK_MAX - 1;

	for ( ; rank >= 0; rank--)
	{
		int rank_min = NXLData::stRank_Rank[idx - rank].SCORE_MIN3;
		int rank_max = NXLData::stRank_Rank[idx - rank].SCORE_MAX2;

		if (rank_min <= rank_point && rank_point <= rank_max)
		{
			break;
		}
	}

	return rank;
}

int GetMaxHP(User * pUser)
{
	int item_hp_sum		= 0;
	for (int i = 0; i < MAX_ITEM_EQUIP_POS; ++i)
	{
		NLogic::Item * pItem = pUser->GetEquip()->GetItem(static_cast<EnumItemEquipPosition>(i));
		if (NULL == pItem)
			continue;

		if (pItem->GetData().eff_type[0] != ITEM_EFFECT_MAX_HP)
			continue;

		item_hp_sum += pItem->GetData().eff_value[0];
	}

	int class_type = pUser->GetCharacterInfo().classtype;
	int stat_con = pUser->GetCharacterInfo().con;

	int hp_constant = 0;

	switch (class_type)
	{
	case CLASS_TYPE_SLASHER:
		hp_constant = NXLData::stPcstatup_Pcstatup[CLASS0_MAX_HP].CON6;
		break;
	case CLASS_TYPE_RANGER:
		hp_constant = NXLData::stPcstatup_Pcstatup[CLASS1_MAX_HP].CON6;
		break;
	case CLASS_TYPE_FIGHTER:
		hp_constant = NXLData::stPcstatup_Pcstatup[CLASS2_MAX_HP].CON6;
		break;
	case CLASS_TYPE_MAGICIAN:
		hp_constant = NXLData::stPcstatup_Pcstatup[CLASS3_MAX_HP].CON6;
		break;
	case CLASS_TYPE_ASSASSIN:
		hp_constant = NXLData::stPcstatup_Pcstatup[CLASS4_MAX_HP].CON6;
		break;
	case CLASS_TYPE_PALADIN:
		hp_constant = NXLData::stPcstatup_Pcstatup[CLASS4_MAX_HP].CON6;
		break;		
	}

	return (stat_con * hp_constant) + item_hp_sum;
}

int GetMaxSP(User * pUser)
{
	int item_sp_sum		= 0;
	for (int i = 0; i < MAX_ITEM_EQUIP_POS; ++i)
	{
		NLogic::Item * pItem = pUser->GetEquip()->GetItem(static_cast<EnumItemEquipPosition>(i));
		if (NULL == pItem)
			continue;

		if (pItem->GetData().eff_type[0] != ITEM_EFFECT_MAX_SP)
			continue;

		item_sp_sum += pItem->GetData().eff_value[0];
	}

	int class_type = pUser->GetCharacterInfo().classtype;
	int stat_spi = pUser->GetCharacterInfo().spi;

	int sp_constant = 0;

	switch (class_type)
	{
	case CLASS_TYPE_SLASHER:
		sp_constant = NXLData::stPcstatup_Pcstatup[CLASS0_MAX_SP].SPI7;
		break;
	case CLASS_TYPE_RANGER:
		sp_constant = NXLData::stPcstatup_Pcstatup[CLASS1_MAX_SP].SPI7;
		break;
	case CLASS_TYPE_FIGHTER:
		sp_constant = NXLData::stPcstatup_Pcstatup[CLASS2_MAX_SP].SPI7;
		break;
	case CLASS_TYPE_MAGICIAN:
		sp_constant = NXLData::stPcstatup_Pcstatup[CLASS3_MAX_SP].SPI7;
		break;
	case CLASS_TYPE_ASSASSIN:
		sp_constant = NXLData::stPcstatup_Pcstatup[CLASS4_MAX_SP].SPI7;
		break;
	case CLASS_TYPE_PALADIN:
		sp_constant = NXLData::stPcstatup_Pcstatup[CLASS4_MAX_SP].SPI7;
		break;		
	}

	return (stat_spi * sp_constant) + item_sp_sum;
}

const char * ReplaceSingleQuotation(const char * srcString)
{
	std::string newString = srcString;
	boost::replace_all(newString, "'", "\\'");
	return newString.c_str();
}

void SendCharacterDefaultInfo(User * pFromUser, User * pToUser)
{
	/*
	 * SC_REQ_USER_INFO_DEFAULT			0x0902
	{
		u32	u32gid;						//게임 유니크 Key
		u16	u16pos_x;
		u16	u16pos_y;
		u16	u16degree;					//방향 벡터(보고있는 방향 0 : RIGHT, 90 : DOWN..)
		u16	u16level;					//레벨(MAX : 99 이상 확장가능)
		u8	u8class_type;				//클래스 타입

		u16	u16main_stat_point;			//메인스탯포인트(잔여포인트)
		u16 u16skill_point;				//스킬포인트(잔여포인트)
		u32	u32main_stat_str;			// MainStat(근력)
		u32	u32main_stat_dex;			// MainStat(민첩)
		u32	u32main_stat_con;			// MainStat(체력)
		u32	u32main_stat_spi;			// MainStat(기력)

		u32	u32ext_stat_exp;			//확장효과(추가경험치 버프)
		u32	u32ext_stat_auto_routing;	//오토루팅 시간
		s16	s16icon_idx;				/// 꾸미기 아이템 인덱스 번호
		u8	u8open_active_skill_num;	// 열린 액티브 스킬 갯수 DLC이슈

		u8	count   max 20 				/// 반복구 : 20회 반복
		{
			u16	u16skill_tid;			///	스킬  TID
			u8	u8skill_levle;			/// 스킬 Level
		}

		str	str_slot_id;
		u8  count 						//	반복구(13회) : 장착아이템 정보
		{
			u8	u8equip_pos;			//	장착위치
			u64	item_seq;				// 아이템 seq
			u8	cur_duration;			// 내구도 현재
			u8	max_duration;
			u8	stack_num;				// 스탯된 개수
			u8	set_type				// 세트아이템타입(-1 : 없음)
			u8	non_identity;   		// 미식별여부
			u8	cur_refine_step;		// 현재 제련단계
			u8	quality;
			u8	level;
			u8	eff_type0;
			u8	eff_pos0;	// 기본이펙트 : 위치
			u16	eff_value0;	// 기본이펙트 : 효과치
			u8	eff_type1;
			u8	eff_pos1;
			u16	eff_value1;
			u8	eff_type2;
			u8	eff_pos2;
			u16	eff_value2;
			u8	eff_type3;
			u8	eff_pos3;
			u16	eff_value3;
			u8	eff_type4;
			u8	eff_pos4;
			u16	eff_value4;
			u8	eff_type5;
			u8	eff_pos5;
			u16	eff_value5;
			u8	eff_type6;
			u8	eff_pos6;
			u16	eff_value6;
			u8	open_upgrade_stone_slot; // 오픈된 강화석 슬롯수
			u8	ablity_enhance_rate; 	// 기본능력치 상향
			u8	max_enhance_step;	// 제련 최대값
			u8	buy_use;	// 구매 후 바로 사용 여부
			u8	evolve_step;	// 진화단계
			u8	evolve_max; 	// 진화 최대단계
			u16	evolve_point;	// 진화포인트
			u16	evolve_eff;
			u16	evolve_eff_value;	// 진화이펙트 값
			u8	class_type;			// 장착클래스 타입
			u8	sheet_type;			// 시트 타입
			u16	tid;				// 테이블 아이디
		}

		/// 가중치
		u16	u16hp_add_percent;				///  기본100 , 그외는 컨트롤
		u16	u16attack_add_percent;			///  기본100 , 그외는 컨트롤

		u16	u16my_pvp_point;		/// 내 PVP승점

		u8	u8gender;					// 성별표시 0:남자, 1:여자, 2:비공개

		/// 버프관련
		count max 5
		{
			u8 u8type;						/// 0:승점버프, 1:친구버프, 2:참피온 버프1 , 3:참피온 버프2, 4:길드 버프
			u16	u16skill_tid;
			u8 u8skill_level;
			s16	s16skill_value;				/// %
			u16	u16skill_time;
		}
	}
	 */

	if (NULL == pFromUser)
		return;

	if (NULL == pToUser)
		return;

	NLogic::Battle::Data & clsBattleData = pFromUser->GetBattle()->GetData();

	NLogic::Equip * pEquip = pFromUser->GetEquip();
	if (NULL == pEquip)
	{
		DEBUGLOG("SendCharacterDefaultInfo FromUser Eqip is NULL");
		return;
	}

	int added_attack = 100;
	int added_hp = 100;
	int posx = 0;
	int posy = 0;

	//if (pFromUser->GetSpace())
	NLogic::Space * pSpace = pFromUser->GetSpace();
	if (NULL != pSpace && pSpace->GetData()._spaceType == NLogic::Space::SpaceType::BATTLEROYAL)
	{
		posx = pFromUser->GetBattleRoyalBattle()->GetData().x;
		posy = pFromUser->GetBattleRoyalBattle()->GetData().y;
	}
	else
	{
		posx = clsBattleData.x;
		posy = clsBattleData.y;
	}

	int degree = clsBattleData.degree;

	// PVP인 경우 HP 및 좌표 보정
	if (NULL != pToUser->GetSpace())
	{
		if (pToUser->GetSpace()->GetData()._spaceType == NLogic::Space::SpaceType::PVP_USER
				|| pToUser->GetSpace()->GetData()._spaceType == NLogic::Space::SpaceType::PVP_PRACTICE
				|| pToUser->GetSpace()->GetData()._spaceType == NLogic::Space::SpaceType::NEW_PVP_ROOM)
		{
			added_hp = NLogic::NFunction::GetAdjustHP(pFromUser);

			// 자신의 좌표를 보고 상대의 좌표를 설정
			if (static_cast<int>(pToUser->GetBattle()->GetData().x) == PVP_P1_START_X)
			{
				posx = PVP_P2_START_X;
				posy = PVP_P2_START_Y;
				degree = 180;
			}
			else
			{
				posx = PVP_P1_START_X;
				posy = PVP_P1_START_Y;
				degree = 0;
			}
		}
		else if (pToUser->GetSpace()->GetData()._spaceType == NLogic::Space::SpaceType::BATTLEROYAL)
		{
			added_hp = NLogic::NFunction::GetAdjustHP(pFromUser, false);
		}
		else if (pToUser->GetSpace()->GetData()._spaceType == NLogic::Space::SpaceType::WORLD && posx == 0 && posy == 0)
		{
			posx = ConstPosX;
			posy = ConstPosY;
		}
	}

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	*pAck << static_cast<uint32_t>(pFromUser->GetUserSeq());
	*pAck << static_cast<uint16_t>(posx);
	*pAck << static_cast<uint16_t>(posy);
	*pAck << static_cast<uint16_t>(degree);
	*pAck << static_cast<uint16_t>(pFromUser->GetCharacterInfo().level);
	*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().classtype);
	*pAck << static_cast<uint16_t>(pFromUser->GetCharacterInfo().remain_stat_point);
	*pAck << static_cast<uint16_t>(pFromUser->GetCharacterInfo().remain_skill_point);

	*pAck << static_cast<uint32_t>(pFromUser->GetCharacterInfo().str);
	*pAck << static_cast<uint32_t>(pFromUser->GetCharacterInfo().dex);
	*pAck << static_cast<uint32_t>(pFromUser->GetCharacterInfo().con);
	*pAck << static_cast<uint32_t>(pFromUser->GetCharacterInfo().spi);

	*pAck << static_cast<uint32_t>(0);		// 확장효과(추가 경험치 버프)
	*pAck << static_cast<uint32_t>(0);		// 오토루팅 시간

	NLogic::Item * pItem = pFromUser->GetEquip()->GetItem(EnumItemEquipPosition::ITEM_EQUIP_POS_NAME_TAG);
	if (NULL != pItem)
		*pAck << static_cast<uint16_t>(pItem->GetData().iconidx);		// 꾸미기 아이템 인덱스 번호
	else
		*pAck << static_cast<uint16_t>(-1);		// 꾸미기 아이템 인덱스 번호

	*pAck << static_cast<uint8_t>(0);		// 열린 액티브 스킬 갯수 DLC이슈

	// 스킬 정보
	*pAck << static_cast<uint8_t>(MAX_SKILL);	// skill count
	//---------------------------------------------------------------------------------------------------------
	// changed by spencer(2014.07.02), 성기사 스킬 추가
	// 성기사 스킬 index: 481~500
	// 기존 class들은 0번부터 순차적으로 data가 입력되어서 기본 공식이 가능함.
	// 성기사 시작 index인 100~ 는 다른 skill이 사용하고 있다. 예외 처리를 하자.
	//---------------------------------------------------------------------------------------------------------
	int iSkillStartIndex = pFromUser->GetCharacterInfo().classtype * MAX_SKILL;
	if ( CLASS_TYPE_PALADIN == pFromUser->GetCharacterInfo().classtype ) // 성기사 스킬
		iSkillStartIndex = 481;//

	for( int i=0 ; i<MAX_SKILL ; i++ )
	{
		*pAck << static_cast<uint16_t>(i + iSkillStartIndex);
		*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().array_Skill[i]);
	}

	if( 1 == pFromUser->GetSocialInfo()->GetData()->_profile_opened )
		* pAck << pFromUser->GetUserInfo().nickname.c_str();
	else
		* pAck << static_cast<uint16_t>(0);

	// 아이템 정보
	// 아이템 장작 정보 중 이름표는 제외
	if (true == pFromUser->GetEquip()->IsExistItem(EnumItemEquipPosition::ITEM_EQUIP_POS_NAME_TAG))
		*pAck << static_cast<uint8_t>(pEquip->HasItemCount() - 1);
	else
		*pAck << static_cast<uint8_t>(pEquip->HasItemCount());

	for(int i = 0; i < static_cast<int>(MAX_ITEM_EQUIP_POS); ++i)
	{
		NLogic::Item * pItem = pEquip->GetItem(static_cast<EnumItemEquipPosition>(i));
		if (NULL != pItem)
		{
			*pAck << static_cast<uint8_t>(pItem->GetEquipPos());
			*pAck << static_cast<uint64_t>(pItem->GetItemSeq());
			pItem->WriteToPacket(pAck);
		}
	}

	// HP 및 공격력 가중치
	*pAck << static_cast<uint16_t>(added_hp);
	*pAck << static_cast<uint16_t>(added_attack);

	// 성별
	int gender = 2;
	if(pFromUser->GetSocialInfo()->GetData()->_isGenderOpen)
	{
		gender = pFromUser->GetSocialInfo()->GetData()->_gender;
	}

	*pAck << static_cast<uint16_t>(pFromUser->GetUserInfo().wp_last_week);
	*pAck << static_cast<uint8_t>(gender);

	// buff
	NLogic::Buff * pBuff = pFromUser->GetBuff();
	if (NULL == pBuff)
	{
		::Network::GETPACKETPOOL()->SEND_DEL(pAck);
		DEBUGLOG("CS_REQ_SKILL_BUFF NULL == pBuff");
		return;
	}

	if (pFromUser == pToUser)
		pBuff->RefleshVIPBuff();

	std::time_t t = std::time(0);  // t is an integer type
	unsigned int nTime = t;

	int nCount = pBuff->GetActiveBuffCount(nTime);

	if (pFromUser == pToUser)
		DEBUGLOG("VIPBUFF %s nCount : %d GID : %d", __FUNCTION__, nCount, pFromUser->GetUserSeq());

//	* pAck << static_cast<uint8_t>(pBuff->GetDataVector().size());
	* pAck << static_cast<uint8_t>(pBuff->GetActiveBuffCount(nTime));

	std::for_each(pBuff->GetDataVector().begin(), pBuff->GetDataVector().end(), [&](NLogic::Buff::Data * pData) {

		if (pData->u8type == static_cast<int>(NLogic::Buff::BuffType::GUILD))
		{
			* pAck << static_cast<uint8_t>(pData->u8type);
			* pAck << static_cast<uint16_t>(pData->u16skill_tid);
			* pAck << static_cast<uint8_t>(pData->u8skill_level);
			* pAck << static_cast<uint16_t>(pData->s16skill_value);
			* pAck << static_cast<uint16_t>(pData->_regdate);
		}
		else
		{
			if (pData->_regdate < nTime)
			{
				pData->Clear();
			}
			else
			{
				* pAck << static_cast<uint8_t>(pData->u8type);
				* pAck << static_cast<uint16_t>(pData->u16skill_tid);
				* pAck << static_cast<uint8_t>(pData->u8skill_level);
				* pAck << static_cast<uint16_t>(pData->s16skill_value);
				if (30000 > pData->_regdate - nTime)
					* pAck << static_cast<uint16_t>(pData->_regdate - nTime);
				else
					* pAck << static_cast<uint16_t>(30000);

				if (pFromUser == pToUser)
				{
					if (pData->u8type == 2 || pData->u8type == 3)
					{
						DEBUGLOG("VIPBUFF %s TYPE : %d BUF TIME : %d GID : %d", __FUNCTION__, pData->u8type, pData->_regdate - nTime, pFromUser->GetUserSeq());
					}
				}
			}
		}
	} );

	* pAck << pFromUser->GetGuildName().c_str();
	* pAck << static_cast<uint8_t>(pFromUser->GetGuildGrade());

	pAck->MakePacket(CMD_SC_REQ_USER_INFO_DEFAULT);
	pToUser->Send(pAck);

//	DEBUGLOG("	##### SendCharacterDefaultInfo : MySeq=%d, OppSeq=%d", pToUser->GetUserSeq(), pFromUser->GetUserSeq());
}

void SendCharacterEquipInfo(User * pFromUser, User * pToUser)
{
	if (NULL == pFromUser)
		return;

	if (NULL == pToUser)
		return;

	NLogic::Equip * pEquip = pFromUser->GetEquip();
	if (NULL == pEquip)
	{
		DEBUGLOG("SendCharacterEquipInfo FromUser Equip is NULL");
		return;
	}

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();

	*pAck << static_cast<uint32_t>(pFromUser->GetUserSeq());

	// 아이템 장작 정보 중 이름표는 제외
	if (true == pFromUser->GetEquip()->IsExistItem(EnumItemEquipPosition::ITEM_EQUIP_POS_NAME_TAG))
		*pAck << static_cast<uint8_t>(pEquip->HasItemCount() - 1);
	else
		*pAck << static_cast<uint8_t>(pEquip->HasItemCount());

	for(int i = 0; i < static_cast<int>(MAX_ITEM_EQUIP_POS); ++i)
	{
		NLogic::Item * pItem = pEquip->GetItem(static_cast<EnumItemEquipPosition>(i));
		if (NULL != pItem)
		{
			*pAck << static_cast<uint8_t>(pItem->GetEquipPos());
			*pAck << static_cast<uint64_t>(pItem->GetItemSeq());
			pItem->WriteToPacket(pAck);
		}
	}

	pAck->MakePacket(CMD_SC_REQ_USER_INFO_EQUIPED);
	pToUser->Send(pAck);

//	DEBUGLOG("	##### SendCharacterEquipInfo : MySeq=%d, OppSeq=%d", pToUser->GetUserSeq(), pFromUser->GetUserSeq());
}

void SendCharacterFairyInfo(User * pFromUser, User * pToUser)
{
	if (NULL == pFromUser)
		return;

	if (NULL == pToUser)
		return;

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();

	*pAck << static_cast<uint32_t>(pFromUser->GetUserSeq());
	*pAck << static_cast<uint8_t>(0);
	*pAck << static_cast<uint8_t>(0);
	*pAck << static_cast<uint8_t>(0);
	*pAck << static_cast<uint8_t>(0);
	*pAck << static_cast<uint8_t>(1);
	*pAck << static_cast<uint8_t>(0);
	*pAck << static_cast<uint32_t>(0);
	*pAck << static_cast<uint32_t>(0);
	*pAck << static_cast<uint8_t>(0);

	pAck->MakePacket(CMD_SC_REQ_USER_INFO_FAIRY);
	pToUser->Send(pAck);

//	DEBUGLOG("	##### SendCharacterFairyInfo : MySeq=%d, OppSeq=%d", pToUser->GetUserSeq(), pFromUser->GetUserSeq());
}

void SendCharacterInvenBagInfo(User * pFromUser, User * pToUser, int bag_type)
{
	if (NULL == pFromUser)
		return;

	if (NULL == pToUser)
		return;

	NLogic::Bag * pBag = pFromUser->GetBag(static_cast<INVEN_BAG_TYPE>(bag_type));
	if (NULL == pBag)
		return;

	int count = pBag->HasItemCount();

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();

	*pAck << static_cast<uint32_t>(pFromUser->GetUserSeq());
	*pAck << static_cast<uint8_t>(bag_type);
	*pAck << static_cast<uint8_t>(count);


	NLogic::Bag::ITEMVECTOR & clsItemVector = pBag->GetItemVector();
	std::for_each(clsItemVector.begin(), clsItemVector.end(), [&](NLogic::Item * pItem) {
		if (NULL != pItem){
			*pAck << static_cast<uint8_t>(pItem->GetData().bag_slot_number);
			*pAck << static_cast<uint64_t>(pItem->GetItemSeq());
			pItem->WriteToPacket(pAck);
		}
	} );

	pAck->MakePacket(CMD_SC_REQ_USER_INFO_INVEN_BAG);
	pToUser->Send(pAck);
}

void SendCharacterInfoSimple(User * pFromUser, User * pToUser)
{
/*	/// 본인을 제외한 다른 유저들의 기본 정보 => 마을 입장시 본인제외한 모든 유저에게 전달
	SN_REQ_OPP_USER_INFO_DEFAULT_VILLIGE	0x092F
	{
			u32	u32gid;						//게임 유니크 Key
			u16	u16pos_x;
			u16	u16pos_y;
			u16	u16degree;					//방향 벡터(보고있는 방향 0 : RIGHT, 90 : DOWN..)
			u16	u16level;					//레벨(MAX : 99 이상 확장가능)
			u8	u8class_type;				//클래스 타입
			str24 str24slot_id;				//슬롯 아이디
			u8 	u8is_ride;					//0 : 내린상태 1: 탄상태

			/// 기본 코스튬 정보
			u8	u8costume_head;
			u8	u8costume_armor;
			u8	u8costume_weapon;
			u8	u8costume_side_hand;
			u8	u8costume_effect;
			u8	u8costume_vehicle;

			/// 페어리정보
			u8	u8quality;					// 등급
			u8	u8eff_type0;				// 페어리 원소타입
			u16	u8eff_value0;				// 페어리 타입

			s16	s16icon_idx;				/// 꾸미기 아이템 인덱스 번호

			u8	u8gender;					// 성별표시 0:남자, 1:여자, 2:비공개
			str	strbirthday;				// 생일
			u8	u8birth_open;				// 생일 공개 여부.
	};*/

	if (NULL == pFromUser)
		return;

	if (NULL == pToUser)
		return;

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();

	*pAck << static_cast<uint32_t>(pFromUser->GetUserSeq());
	*pAck << static_cast<uint16_t>(pFromUser->GetBattle()->GetData().x);
	*pAck << static_cast<uint16_t>(pFromUser->GetBattle()->GetData().y);
	*pAck << static_cast<uint16_t>(pFromUser->GetBattle()->GetData().degree);
	*pAck << static_cast<uint16_t>(pFromUser->GetCharacterInfo().level);
	*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().classtype);


	DEBUGLOG("FLOW> SendCharacterInfoSimple()> userseq: %d", pFromUser->GetUserSeq());

	// 프로필 공개 여부
	if(1 == pFromUser->GetSocialInfo()->GetData()->_profile_opened)
	{
		if (81 <= pFromUser->GetUserInfo().nickname.size())
		{
			DEBUGLOG("SendCharacterInfoSimple user nick : %s", pFromUser->GetUserInfo().nickname.c_str());
			Toolkit::Str<4> unknownNickname = "none";
			*pAck << unknownNickname.c_str();
		}
		else
		{
			*pAck << pFromUser->GetUserInfo().nickname.c_str();
		}
	}
	else
	{
		*pAck << static_cast<uint16_t>(0);
	}

	//*pAck << static_cast<uint8_t>(pFromUser->GetBattle()->GetData().vehicle_state);
	*pAck << static_cast<uint8_t>(pFromUser->GetVehicleState());

	// 기본 코스튬 정보
	if (pFromUser->GetCharacterInfo().avartar_iconidx == 1000)
	{
		*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().helmet_iconidx);
		*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().armor_iconidx);
		*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().weapon_iconidx);
		*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().weapon_iconidx);
	}
	else
	{
		*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().avartar_iconidx + 100);
		*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().avartar_iconidx + 100);
		*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().avartar_iconidx + 100);
		*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().avartar_iconidx + 100);
	}

	*pAck << static_cast<uint8_t>(0);		// costume_effect
	*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().vehicle_iconidx);

	// 페어리 정보
	*pAck << static_cast<uint8_t>(0);
	*pAck << static_cast<uint8_t>(0);
	*pAck << static_cast<uint16_t>(0);

	NLogic::Bag * pBag = pFromUser->GetBag(static_cast<INVEN_BAG_TYPE>(INVEN_BAG_TYPE::BAG_TYPE_MISC));
	if (NULL != pBag)
	{
		// 마을 입장 전에 이름표 장착 정보 로드
		if (false == pBag->IsLoad())
		{
			pBag->ItemLoadFromDatabase();
			pFromUser->GetEquip()->EquipAddFromCharacterInfo( 200 );
		}
	}

	NLogic::Item * pItem = pFromUser->GetEquip()->GetItem(EnumItemEquipPosition::ITEM_EQUIP_POS_NAME_TAG);

	if (NULL != pItem)
		*pAck << static_cast<uint16_t>(pItem->GetData().iconidx);		// 꾸미기 아이템 인덱스 번호
	else
		*pAck << static_cast<uint16_t>(-1);		// 꾸미기 아이템 인덱스 번호

	// 성별 정보
	int gender = 2;
	if(pFromUser->GetSocialInfo()->GetData()->_isGenderOpen)
	{
		gender = pFromUser->GetSocialInfo()->GetData()->_gender;
	}

	*pAck << static_cast<uint8_t>(gender);
	*pAck << pFromUser->GetSocialInfo()->GetData()->_birthday.c_str();
	*pAck << static_cast<uint8_t>(pFromUser->GetSocialInfo()->GetData()->_isBirthdayOpen);

	*pAck << pFromUser->GetGuildName().c_str();
	*pAck << static_cast<uint8_t>(pFromUser->GetGuildGrade());

	pAck->MakePacket(CMD_SC_REQ_OPP_USER_INFO_DEFAULT_VILLAGE);
	pToUser->Send(pAck);
}

void SendCharacterDetailInfo(int fromUserSeq, User * pToUser)
{
/*	CS_REQ_USER_INFO_DETAIL			0x0944
	{
		u32	u32gid;						//게임 유니크 Key
	}

	SC_REQ_USER_INFO_DETAIL			0x0945
	{
		u16	u16level;					//레벨(MAX : 99 이상 확장가능)
		u32	u32main_stat_str;			// MainStat(근력)
		u32	u32main_stat_dex;			// MainStat(민첩)
		u32	u32main_stat_con;			// MainStat(체력)
		u32	u32main_stat_spi;			// MainStat(기력)

		u8	u8open_active_skill_num;	// 열린 액티브 스킬 갯수 DLC이슈
		u8	count   max 20 				/// 반복구 : 20회 반복
		{
			u16	u16skill_tid;			///	스킬  TID
			u8	u8skill_levle;			/// 스킬 Level
		}

		u8  count 						//	반복구(13회) : 장착아이템 정보
		{
			u8	u8equip_pos;			//	장착위치
			u64	item_seq;				// 아이템 seq
			u8	cur_duration;			// 내구도 현재
			u8	max_duration;
			u8	stack_num;				// 스탯된 개수
			u8	set_type				// 세트아이템타입(-1 : 없음)
			u8	non_identity;   		// 미식별여부
			u8	cur_refine_step;		// 현재 제련단계
			u8	quality;
			u8	level;
			u8	eff_type0;
			u8	eff_pos0;	// 기본이펙트 : 위치
			u16	eff_value0;	// 기본이펙트 : 효과치
			u8	eff_type1;
			u8	eff_pos1;
			u16	eff_value1;
			u8	eff_type2;
			u8	eff_pos2;
			u16	eff_value2;
			u8	eff_type3;
			u8	eff_pos3;
			u16	eff_value3;
			u8	eff_type4;
			u8	eff_pos4;
			u16	eff_value4;
			u8	eff_type5;
			u8	eff_pos5;
			u16	eff_value5;
			u8	eff_type6;
			u8	eff_pos6;
			u16	eff_value6;
			u8	open_upgrade_stone_slot; // 오픈된 강화석 슬롯수
			u8	ablity_enhance_rate; 	// 기본능력치 상향
			u8	max_enhance_step;	// 제련 최대값
			u8	buy_use;	// 구매 후 바로 사용 여부
			u8	evolve_step;	// 진화단계
			u8	evolve_max; 	// 진화 최대단계
			u16	evolve_point;	// 진화포인트
			u16	evolve_eff;
			u16	evolve_eff_value;	// 진화이펙트 값
			u8	class_type;			// 장착클래스 타입
			u8	sheet_type;			// 시트 타입
			u16	tid;				// 테이블 아이디
		}
	}*/

	if (NULL == pToUser)
		return;

	User * pFromUser = ::ProjectZ::NProxy::GetUser(fromUserSeq);
	if (NULL == pFromUser)
		return;

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();

	*pAck << static_cast<uint16_t>(pFromUser->GetCharacterInfo().level);
	*pAck << static_cast<uint32_t>(pFromUser->GetCharacterInfo().str);
	*pAck << static_cast<uint32_t>(pFromUser->GetCharacterInfo().dex);
	*pAck << static_cast<uint32_t>(pFromUser->GetCharacterInfo().con);
	*pAck << static_cast<uint32_t>(pFromUser->GetCharacterInfo().spi);

	*pAck << static_cast<uint8_t>(0);
	*pAck << static_cast<uint8_t>(MAX_SKILL);
	for( int i=0 ; i<MAX_SKILL ; i++ )
	{
		*pAck << static_cast<uint16_t>(i + (pFromUser->GetCharacterInfo().classtype * MAX_SKILL));
		*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().array_Skill[i]);
	}

	NLogic::Equip * pEquip = pFromUser->GetEquip();
	if (NULL == pEquip)
	{
		::Network::GETPACKETPOOL()->SEND_DEL(pAck);
		DEBUGLOG("SendCharacterDetailInfo FromUser Equip is NULL");
		return;
	}

	// 아이템 장작 정보 중 이름표는 제외
	if (true == pFromUser->GetEquip()->IsExistItem(EnumItemEquipPosition::ITEM_EQUIP_POS_NAME_TAG))
		*pAck << static_cast<uint8_t>(pEquip->HasItemCount() - 1);
	else
		*pAck << static_cast<uint8_t>(pEquip->HasItemCount());

	for(int i = 0; i < static_cast<int>(MAX_ITEM_EQUIP_POS); ++i)
	{
		NLogic::Item * pItem = pEquip->GetItem(static_cast<EnumItemEquipPosition>(i));
		if (NULL != pItem)
		{
			*pAck << static_cast<uint8_t>(pItem->GetEquipPos());
			*pAck << static_cast<uint64_t>(pItem->GetItemSeq());
			pItem->WriteToPacket(pAck);
		}
	}

	pAck->MakePacket(CMD_SC_REQ_USER_INFO_DETAIL);
	pToUser->Send(pAck);
}

void SendAICharacterDefaultInfo(User * pFromUser, User * pToUser)
{
	/*
	 * SC_REQ_USER_INFO_DEFAULT			0x0902
	{
		u32	u32gid;						//게임 유니크 Key
		u16	u16pos_x;
		u16	u16pos_y;
		u16	u16degree;					//방향 벡터(보고있는 방향 0 : RIGHT, 90 : DOWN..)
		u16	u16level;					//레벨(MAX : 99 이상 확장가능)
		u8	u8class_type;				//클래스 타입

		u16	u16main_stat_point;			//메인스탯포인트(잔여포인트)
		u16 u16skill_point;				//스킬포인트(잔여포인트)
		u32	u32main_stat_str;			// MainStat(근력)
		u32	u32main_stat_dex;			// MainStat(민첩)
		u32	u32main_stat_con;			// MainStat(체력)
		u32	u32main_stat_spi;			// MainStat(기력)

		u32	u32ext_stat_exp;			//확장효과(추가경험치 버프)
		u32	u32ext_stat_auto_routing;	//오토루팅 시간
		u16	u16zen_sub_stat;			//젠으로 찍은 서브스탯포인트
		u8	u8open_active_skill_num;	// 열린 액티브 스킬 갯수 DLC이슈

		u8	count   max 20 				/// 반복구 : 20회 반복
		{
			u16	u16skill_tid;			///	스킬  TID
			u8	u8skill_levle;			/// 스킬 Level
		}

		str	str_slot_id;
		u8  count 						//	반복구(13회) : 장착아이템 정보
		{
			u8	u8equip_pos;			//	장착위치
			u64	item_seq;				// 아이템 seq
			u8	cur_duration;			// 내구도 현재
			u8	max_duration;
			u8	stack_num;				// 스탯된 개수
			u8	set_type				// 세트아이템타입(-1 : 없음)
			u8	non_identity;   		// 미식별여부
			u8	cur_refine_step;		// 현재 제련단계
			u8	quality;
			u8	level;
			u8	eff_type0;
			u8	eff_pos0;	// 기본이펙트 : 위치
			u16	eff_value0;	// 기본이펙트 : 효과치
			u8	eff_type1;
			u8	eff_pos1;
			u16	eff_value1;
			u8	eff_type2;
			u8	eff_pos2;
			u16	eff_value2;
			u8	eff_type3;
			u8	eff_pos3;
			u16	eff_value3;
			u8	eff_type4;
			u8	eff_pos4;
			u16	eff_value4;
			u8	eff_type5;
			u8	eff_pos5;
			u16	eff_value5;
			u8	eff_type6;
			u8	eff_pos6;
			u16	eff_value6;
			u8	open_upgrade_stone_slot; // 오픈된 강화석 슬롯수
			u8	ablity_enhance_rate; 	// 기본능력치 상향
			u8	max_enhance_step;	// 제련 최대값
			u8	buy_use;	// 구매 후 바로 사용 여부
			u8	evolve_step;	// 진화단계
			u8	evolve_max; 	// 진화 최대단계
			u16	evolve_point;	// 진화포인트
			u16	evolve_eff;
			u16	evolve_eff_value;	// 진화이펙트 값
			u8	class_type;			// 장착클래스 타입
			u8	sheet_type;			// 시트 타입
			u16	tid;				// 테이블 아이디
		}

		/// 가중치
		u16	u16hp_add_percent;				///  기본100 , 그외는 컨트롤
		u16	u16attack_add_percent;			///  기본100 , 그외는 컨트롤

		u16	u16my_pvp_point;		/// 내 PVP승점

		u8	u8gender;					// 성별표시 0:남자, 1:여자, 2:비공개

		/// 버프관련
		count max 5
		{
			u8 u8type;						/// 0:승점버프, 1:친구버프, 2:참피온 버프1 , 3:참피온 버프2, 4:길드 버프
			u16	u16skill_tid;
			u8 u8skill_level;
			s16	s16skill_value;				/// %
			u16	u16skill_time;
		}
	}
	 */
	if (NULL == pFromUser)
		return;

	if (NULL == pToUser)
		return;

	NLogic::Equip * pEquip = pFromUser->GetEquip();
	if (NULL == pEquip)
	{
		DEBUGLOG("SendAICharacterDefaultInfo FromUser Equip is NULL");
		return;
	}

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();

	if (true == pToUser->GetSpace()->GetData()._bPVPDummyUser)
	{
		*pAck << static_cast<uint32_t>(0);
	}
	else
	{
		*pAck << static_cast<uint32_t>(pFromUser->GetUserSeq());
	}

	*pAck << static_cast<uint16_t>(PVP_P2_START_X);
	*pAck << static_cast<uint16_t>(PVP_P2_START_Y);
	*pAck << static_cast<uint16_t>(180);
	*pAck << static_cast<uint16_t>(pFromUser->GetCharacterInfo().level);
	*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().classtype);
	*pAck << static_cast<uint16_t>(pFromUser->GetCharacterInfo().remain_stat_point);
	*pAck << static_cast<uint16_t>(pFromUser->GetCharacterInfo().remain_skill_point);

	*pAck << static_cast<uint32_t>(pFromUser->GetCharacterInfo().str);
	*pAck << static_cast<uint32_t>(pFromUser->GetCharacterInfo().dex);
	*pAck << static_cast<uint32_t>(pFromUser->GetCharacterInfo().con);
	*pAck << static_cast<uint32_t>(pFromUser->GetCharacterInfo().spi);

	*pAck << static_cast<uint32_t>(0);		// 확장효과(추가 경험치 버프)
	*pAck << static_cast<uint32_t>(0);		// 오토루팅 시간
	*pAck << static_cast<uint16_t>(0);		// 젠으로 찍은 서브스탯포인트
	*pAck << static_cast<uint8_t>(0);		// 열린 액티브 스킬 갯수 DLC이슈

	*pAck << static_cast<uint8_t>(MAX_SKILL);
	for( int i=0 ; i<MAX_SKILL ; i++ )
	{
		*pAck << static_cast<uint16_t>(i + (pFromUser->GetCharacterInfo().classtype * MAX_SKILL));
		*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().array_Skill[i]);
	}

	if( 1 == pFromUser->GetSocialInfo()->GetData()->_profile_opened )
		* pAck << pFromUser->GetUserInfo().nickname.c_str();
	else
		* pAck << static_cast<uint16_t>(0);

	// 아이템 장작 정보 중 이름표는 제외
	if (true == pFromUser->GetEquip()->IsExistItem(EnumItemEquipPosition::ITEM_EQUIP_POS_NAME_TAG))
		*pAck << static_cast<uint8_t>(pEquip->HasItemCount() - 1);
	else
		*pAck << static_cast<uint8_t>(pEquip->HasItemCount());

	for(int i = 0; i < static_cast<int>(MAX_ITEM_EQUIP_POS); ++i)
	{
		NLogic::Item * pItem = pEquip->GetItem(static_cast<EnumItemEquipPosition>(i));
		if (NULL != pItem)
		{
			*pAck << static_cast<uint8_t>(pItem->GetEquipPos());
			*pAck << static_cast<uint64_t>(pItem->GetItemSeq());
			pItem->WriteToPacket(pAck);
		}
	}

	int added_hp = 100;
	int added_attack = 100;

	// PVP인 경우 HP 보정
	if (pToUser->GetSpace()->GetData()._spaceType == NLogic::Space::SpaceType::PVP_PRACTICE)
	{
		added_hp = NLogic::NFunction::GetAdjustHP(pFromUser);
	}

	*pAck << static_cast<uint16_t>(added_hp);
	*pAck << static_cast<uint16_t>(added_attack);

	int gender = 2;
	if(pToUser->GetSocialInfo()->GetData()->_isGenderOpen)
	{
		gender = pToUser->GetSocialInfo()->GetData()->_gender;
	}

	*pAck << static_cast<uint16_t>(pToUser->GetUserInfo().wp_last_week);
	*pAck << static_cast<uint8_t>(gender);

	// buff
	*pAck << static_cast<uint8_t>(0);

	*pAck << pFromUser->GetGuildName().c_str();
	*pAck << static_cast<uint8_t>(pFromUser->GetGuildGrade());

	pAck->MakePacket(CMD_SC_REQ_USER_INFO_DEFAULT);
	pToUser->Send(pAck);

//	DEBUGLOG("	##### SendAICharacterDefaultInfo : MySeq=%d, OppSeq=%d", pToUser->GetUserSeq(), pFromUser->GetUserSeq());
}

void SendAICharacterEquipInfo(User * pFromUser, User * pToUser)
{
	if (NULL == pFromUser)
		return;

	if (NULL == pToUser)
		return;

	NLogic::Equip * pEquip = pFromUser->GetEquip();
	if (NULL == pEquip)
	{
		DEBUGLOG("SendCharacterEquipInfo FromUser Eqip is NULL");
		return;
	}

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();

	if (true == pToUser->GetSpace()->GetData()._bPVPDummyUser)
	{
		*pAck << static_cast<uint32_t>(0);
	}
	else
	{
		*pAck << static_cast<uint32_t>(pFromUser->GetUserSeq());
	}

	// 아이템 장작 정보 중 이름표는 제외
	if (true == pFromUser->GetEquip()->IsExistItem(EnumItemEquipPosition::ITEM_EQUIP_POS_NAME_TAG))
		*pAck << static_cast<uint8_t>(pEquip->HasItemCount() - 1);
	else
		*pAck << static_cast<uint8_t>(pEquip->HasItemCount());

	for(int i = 0; i < static_cast<int>(MAX_ITEM_EQUIP_POS); ++i)
	{
		NLogic::Item * pItem = pEquip->GetItem(static_cast<EnumItemEquipPosition>(i));
		if (NULL != pItem)
		{
			*pAck << static_cast<uint8_t>(pItem->GetEquipPos());
			*pAck << static_cast<uint64_t>(pItem->GetItemSeq());
			pItem->WriteToPacket(pAck);
		}
	}

	pAck->MakePacket(CMD_SC_REQ_USER_INFO_EQUIPED);
	pToUser->Send(pAck);

//	DEBUGLOG("	##### SendAICharacterEquipInfo : MySeq=%d, OppSeq=%d", pToUser->GetUserSeq(), pFromUser->GetUserSeq());
}

void SendAICharacterQuickSlotInfo(User * pFromUser, User * pToUser)
{
	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();

	if (true == pToUser->GetSpace()->GetData()._bPVPDummyUser)
	{
		*pAck << static_cast<uint32_t>(0);
	}
	else
	{
		*pAck << static_cast<uint32_t>(pFromUser->GetUserSeq());
	}

	*pAck << static_cast<uint8_t>(8);

	for(int i = 0; i < 8; i++)
	{
		*pAck << static_cast<uint8_t>(i);
		*pAck << static_cast<uint8_t>(pFromUser->GetCharacterInfo().array_QuickSlot[i].type);
		*pAck << static_cast<uint64_t>(pFromUser->GetCharacterInfo().array_QuickSlot[i].index);
	}

	pAck->MakePacket(CMD_SC_REQ_USER_INFO_QUICKSLOT);
	pToUser->Send(pAck);

//	DEBUGLOG("	##### SendAICharacterQuickSlotInfo : MySeq=%d, OppSeq=%d", pToUser->GetUserSeq(), pFromUser->GetUserSeq());
}

void 				SendExceptionNoSpace(User * pUser)
{
	::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pNoti << static_cast<int16_t>(ACK_NO_SPACE);
	pNoti->MakePacket(CMD_SN_SERVER_EXCEPTION);
	pUser->Send(pNoti);
}

void 				SendExceptionNoParty(User * pUser)
{
	::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pNoti << static_cast<int16_t>(ACK_NO_PARTY);
	pNoti->MakePacket(CMD_SN_SERVER_EXCEPTION);
	pUser->Send(pNoti);
}

void	SendInvenItemUpdate(User * pUser, Item * item)
{
/*	/// 인벤에 특정아이템 변경 시 서버에서 내려주는 패킷
	SN_INVEN_ITEM_UPDATE			0x0955
	{
		u64	item_seq;				// 아이템 seq
		u8	cur_duration;			// 내구도 현재
		u8	max_duration;
		u8	stack_num;				// 스탯된 개수
		u8	set_type				// 세트아이템타입(-1 : 없음)
		u8	non_identity;   		// 미식별여부
		u8	cur_refine_step;		// 현재 제련단계
		u8	quality;
		u8	level;
		u8	eff_type0;
		u8	eff_pos0;	// 기본이펙트 : 위치
		u16	eff_value0;	// 기본이펙트 : 효과치
		u8	eff_type1;
		u8	eff_pos1;
		u16	eff_value1;
		u8	eff_type2;
		u8	eff_pos2;
		u16	eff_value2;
		u8	eff_type3;
		u8	eff_pos3;
		u16	eff_value3;
		u8	eff_type4;
		u8	eff_pos4;
		u16	eff_value4;
		u8	eff_type5;
		u8	eff_pos5;
		u16	eff_value5;
		u8	eff_type6;
		u8	eff_pos6;
		u16	eff_value6;
		u8	open_upgrade_stone_slot; // 오픈된 강화석 슬롯수
		u8	ablity_enhance_rate; 	// 기본능력치 상향
		u8	max_enhance_step;	// 제련 최대값
		u8	belongItem;					/// 귀속 여부, 0 : 일반, 1 : 착용시 귀속(미착용), 2 : 착용시 귀속(착용), 3 : 획득시 귀속
		u8	evolve_step;	// 진화단계
		u8	evolve_max; 	// 진화 최대단계
		u16	evolve_point;	// 진화포인트
		u16	evolve_eff;
		u16	evolve_eff_value;	// 진화이펙트 값
		u8	class_type;			// 장착클래스 타입
		u8	sheet_type;			// 시트 타입
		u16	tid;				// 테이블 아이디
	}	*/

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	*pAck << static_cast<uint64_t>(item->GetItemSeq());
	item->WriteToPacket(pAck);
	pAck->MakePacket(CMD_SN_INVEN_ITEM_UPDATE);
	pUser->Send(pAck);
}

void
SendSkillBuff(User * pUser)
{
	NLogic::Buff * pBuff = pUser->GetBuff();
	if (NULL == pBuff)
	{
		DEBUGLOG("%s : pBuff is NULL");
		return;
	}

	pBuff->RefleshVIPBuff();

	std::time_t t = std::time(0);  // t is an integer type
	unsigned int nTime = t;

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pAck << static_cast<int16_t>(ACK_OK);
	* pAck << pUser->GetUserSeq();
	* pAck << static_cast<uint8_t>(pBuff->GetActiveBuffCount(nTime));

	DEBUGLOG("%s> user_seq: %d, count: %d", __FUNCTION__, pUser->GetUserSeq(), pBuff->GetActiveBuffCount(nTime));

	int iTemp = 0;
	std::for_each(pBuff->GetDataVector().begin(), pBuff->GetDataVector().end(), [&](NLogic::Buff::Data * pData) {

		DEBUGLOG("%s> user_seq: %d, iTemp: %d", __FUNCTION__, pUser->GetUserSeq(), iTemp);
		++iTemp;

		if (pData->u8type == static_cast<int>(NLogic::Buff::BuffType::GUILD))
		{
			* pAck << static_cast<uint8_t>(pData->u8type);
			* pAck << static_cast<uint16_t>(pData->u16skill_tid);
			* pAck << static_cast<uint8_t>(pData->u8skill_level);
			* pAck << static_cast<uint16_t>(pData->s16skill_value);
			* pAck << static_cast<uint16_t>(pData->_regdate);
		}
		else
		{
			if (pData->_regdate < nTime)
			{
				pData->Clear();
			}
			else
			{
				* pAck << static_cast<uint8_t>(pData->u8type);
				* pAck << static_cast<uint16_t>(pData->u16skill_tid);
				* pAck << static_cast<uint8_t>(pData->u8skill_level);
				* pAck << static_cast<uint16_t>(pData->s16skill_value);
				if (30000 > pData->_regdate - nTime)
					* pAck << static_cast<uint16_t>(pData->_regdate - nTime);
				else
					* pAck << static_cast<uint16_t>(30000);

				if (pData->u8type == 2 || pData->u8type == 3)
				{
					DEBUGLOG("VIPBUFF %s TYPE : %d GID : %d", __FUNCTION__, pData->u8type, pUser->GetUserSeq());
				}
			}
		}
	} );

	pAck->MakePacket(CMD_SC_REQ_SKILL_BUFF);
	pUser->Send(pAck);
}

bool
IsRegisterUser(int user_seq)
{
	::Database::Command::Auto clsAuto(::Database::GETCOMMANDPOOL());
	clsAuto->SetQueryType(::Database::Command::SELECT);
	clsAuto->MakeQuery("select unregister_time from info_login where seq = %d limit 1", user_seq);

	if (false == ::Database::GETSESSION()->SyncExecute(static_cast<int>(DatabaseType::GAME_SLAVE), clsAuto))
	{
		DEBUGLOG("%s : Oops! Query Execute Fail", __FUNCTION__);
		return false;
	}

	if (clsAuto->GetErrorIdx() != 0)
	{
		DEBUGLOG("%s : Oops! Occur Error. Query[%s] ", __FUNCTION__, clsAuto->GetQueryString());
		return false;
	}

	if (0 == clsAuto->ResultRowCount())
	{
		DEBUGLOG("%s : Oops! Not Exists User=%d ", __FUNCTION__, user_seq);
		return false;
	}

	uint64_t unregister_time = 0;
	while( clsAuto->Next() )
	{
		clsAuto->GetRecord() >> unregister_time;
	}

	// 탈퇴하지 않은 유저
	if (0 == unregister_time)
	{
		return true;
	}

	return false;
}

void
StringSplit(std::string & targetString, char separator, std::vector<std::string> & resultVector)
{
	int size = targetString.length();
	int start = 0;
	int stop = 0;

	start = targetString.find_first_not_of(separator);

	while ( (start >= 0) && (start < size) )
	{
		stop = targetString.find_first_of(separator, start);

		if ( (stop < 0) || (stop > size) )
		{
			stop = size;
		}

		resultVector.push_back(targetString.substr(start, stop - start));

		start = targetString.find_first_not_of(separator, stop + 1);
	}
}

void
StringToIntSplit(std::string & targetString, char separator, std::vector<int> & resultVector)
{
	int size = targetString.length();
	int start = 0;
	int stop = 0;

	start = targetString.find_first_not_of(separator);

	while ( (start >= 0) && (start < size) )
	{
		stop = targetString.find_first_of(separator, start);

		if ( (stop < 0) || (stop > size) )
		{
			stop = size;
		}

		resultVector.push_back(atoi(targetString.substr(start, stop - start).c_str()));

		start = targetString.find_first_not_of(separator, stop + 1);
	}
}

bool
IncreaseExpFairy(NLogic::Item * pItem, int exp, int maxLevel)
{
	int curExp = pItem->GetData().evolve_value + exp;
	int maxExp = getMaxExpFairy(pItem);

	bool bLevelUp = false;

	while (curExp >= maxExp)
	{
		bLevelUp = true;

		curExp -= maxExp;

		pItem->GetData().level++;

		maxExp = getMaxExpFairy(pItem);

		if (pItem->GetData().level >= maxLevel)
		{
			pItem->GetData().level = maxLevel;
			pItem->GetData().evolve_value = 0;
			break;
		}
	}

	// 페어리 레벨이 MAX레벨보다 작은 경우에만 남은 경험치 부여.
	if (pItem->GetData().level < maxLevel)
	{
		pItem->GetData().evolve_value = curExp;
	}

	return bLevelUp;
}

int
getMaxExpFairy(NLogic::Item * pItem)
{
	// 다음 레벨업 필요 경험치 = 등급 * (현재레벨)^2 / 2

	return (pItem->GetData().quality + 1) * pow(pItem->GetData().level, 2) / 2;
}

} /*NFunction*/ } /*NLogic*/ } /* namespace ProjectZ */
